#include <dt-bindings/gpio/gpio.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/err.h>


#include <linux/workqueue.h>  //添加对应头文件


//用新的gpio接口
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>



static struct gpio_desc* mygpio1;
static int num1 ; 

static struct gpio_desc* mygpio2;
static int num2 ; 
int dir; 
int value;
int irq; 

struct pinctrl* led_pinctrl;
struct pinctrl_state* led_state;

int ret ;

/*****
 *  14-GPIO子系统与pinctrl子系统相结合
 * 	led_ctrl:led_ctrl_gpio4 {
        //   status = "disabled";
		    status = "okay";
            compatible = "rk3568_led_ctrl";
            redgpio-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
		    pinctrl-names = "myled1";
            pinctrl-0 = <&led_ctrl_gpio>;
    };

&pinctrl {
	 my_led_ctrl{ 
		led_ctrl_gpio:led_ctrl_gpio-pins{
			// RK_FUNC_GPIO 这个是宏0,1,2,3
                rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
		};
	};
}

 *
 学习1：
 *   函数：
 *  1. gpiod_direction_output  设置输入输出
     2.gpiod_set_value  拉高拉低
       3. gpiod_get_direction  判断输入输出
 *    4. gpiod_get_value  获取高低电平
 *   5. gpiod_to_irq    获取中断号

 *    
 */

// 第一章：驱动开发
static int led_ctrl_probe(struct platform_device *pdev) //compatible的属性和dts的compatible一致，就会调用probe函数
{

//11. 新API函数使用
    mygpio1 =  gpiod_get_optional(&pdev->dev,"redgpio",0);
	if(mygpio1 == NULL){
		printk("gpiod_get1 fail");
		return -1;
	}; 
	 num1 =  desc_to_gpio(mygpio1);
     printk("num is1  %d  \n", num1);

    
//需要释放，下面才可用
    gpiod_put(mygpio1);
  //多了一个index 
	mygpio2 =  gpiod_get_index(&pdev->dev,"redgpio",0,0);
    if(IS_ERR(mygpio2)){
     	printk("gpiod_get2 fail");
		return -1;
	}	 
	 num2 =  desc_to_gpio(mygpio2);
     printk("num is  %d  \n", num2);

	//workqueue_init_led();

    gpiod_direction_output(mygpio1,0);  // 设置为输出低电平 


    gpiod_set_value(mygpio1,1); // 设置为高电平

	dir = gpiod_get_direction(mygpio1);
	if(dir == GPIOF_DIR_IN){
           printk("gpio input ..  ");
	}else if(dir == GPIOF_DIR_OUT ){
		    printk("gpio output ..  ");
	}
    
	value = gpiod_get_value(mygpio1);
	printk("value is %d\n ..  ",value);

	irq = gpiod_to_irq(mygpio1);   //申请外部中断
	printk("irq is %d\n ..  ",irq);



	printk("bottom");
	return 0;
}


static int led_ctrl_remove(struct platform_device *pdv)
{
	return 0;
}


static struct of_device_id led_ctrl_match_table [] = {
	{.compatible = "rk3568_led_ctrl",}, //这里应该要跟dts的.compatible保持一致，我这里视频课程中没有写成一样，
        {},						//但他有个模糊匹配的功能，就是匹配相近的字段, 为了防止出错，大家最好写成跟dts一样的字段
	};

static struct platform_driver led_ctrl_driver = {
        .driver         = {
                .name = "rk3568_led_ctrl",
		.owner = THIS_MODULE, 
                .of_match_table = led_ctrl_match_table,
        },
        .probe          = led_ctrl_probe,
	.remove = led_ctrl_remove,
};

static int led_ctrl_init(void)
{
	printk("%s(), __%d__\n", __func__, __LINE__);

	platform_driver_register(&led_ctrl_driver); //注册platform平台总线驱动
	return 0;
}

static void led_ctrl_exit(void)
{
	printk("%s(), __%d__\n", __func__, __LINE__);

    gpiod_put(mygpio2);
	
	platform_driver_unregister(&led_ctrl_driver); //注销驱动
}


module_init(led_ctrl_init); //模块加载函数, linux启动， insmod 驱动的时候 
module_exit(led_ctrl_exit); //模块卸载函数

MODULE_AUTHOR("caigong, 214241976@qq.com");   // 邮箱
MODULE_DESCRIPTION("Control Led Driver");    //作者
MODULE_LICENSE("GPL");       //驱动遵守的开源协议GPL
